#include <iostream>
#include <sstream>
#include "MapIO.h"
#include "MacroDef.h"

using namespace std;

MapIO :: MapIO()
{
	screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 0, SDL_SWSURFACE);
	if(!screen)
	{
		cerr << "[ERROR]: " << SDL_GetError() << endl;
		exit(1);
	}

	background = loadImg("pics\\bg1.bmp");

	loadElement();
	
	TTF_Init();
	arialFont = loadFont("tools\\arial.ttf", 20);
	
	camera.x = 0; camera.y = 0; camera.w = SCREEN_WIDTH; camera.h = SCREEN_HEIGHT;
	int** a;
	a = new int*[3];
	for(int i = 0; i < 3; i++)
		a[i] = new int[3];

	dot = new Dot(this);
	manager = new Manager(this, dot);
	timer = new Timer();
	bg = new Background*[BG_NUM];
	setBg();

	applySurface(0, 0, background, screen);
	applySurface(dot->getX(), dot->getY(), dot->getDotImg(), screen);
	setInfoSurface();
	SDL_Flip(screen);
}

MapIO :: ~MapIO()
{
	SDL_FreeSurface(screen);
	SDL_FreeSurface(background);
	TTF_CloseFont(arialFont);

	delete timer;
	delete dot;
	delete manager;
}

void MapIO :: getInput()
{
	bool quit = false;
	SDL_Event event;

	while(!quit)
	{
		timer->start();

		while(SDL_PollEvent(&event))
		{
			if(event.type == SDL_QUIT)
				quit = true;
		}

		manager->process();
	}
}

void MapIO :: output()
{
	showBg();
	showMap();
	applySurface(dot->getX()-camera.x, dot->getY()-camera.y, dot->getDotImg(), screen);
	setInfoSurface();
	SDL_Flip(screen);
	while(timer->getTicks() < 1000 / FPS)
	{
	}
}

void MapIO :: applySurface(int x, int y, SDL_Surface* source, SDL_Surface* dest, SDL_Rect* clip)
{
	SDL_Rect offset;
	offset.x = x;
	offset.y = y;

	SDL_BlitSurface(source, clip, dest, &offset);
}

void MapIO :: setInfoSurface()
{
	SDL_Color textColor = {0, 0, 0};
	SDL_Surface* infoSurface;
	string xStr = conToString(dot->getX());
	string yStr = conToString(dot->getY());
	string xReduceStr = conToString((dot->getX()/ SIZEX));
	string yReduceStr = conToString((dot->getY()/SIZEY));
	string infoStr = "(" + xStr + ", " + yStr +")" + " " + "(" + xReduceStr + ", " + yReduceStr + ")";
	
	infoSurface = TTF_RenderText_Solid(arialFont, infoStr.c_str(), textColor);
	applySurface(0, 0, infoSurface, screen);

	SDL_FreeSurface(infoSurface);
}

void MapIO :: showBg()
{
	SDL_Rect* box;
	for(int i = 0; i < BG_NUM; i++)
	{
		box = bg[i]->getBox();
		if(checkCollision(&camera, box))
			applySurface(box->x - camera.x, box->y - camera.y, bg[i]->getBg(), screen);
	}
}
void MapIO :: showMap()
{
	SDL_Rect element;
	element.w = SIZEX;
	element.h = SIZEY;
	
	for(int i = 0; i < LEVEL_HEIGHT / SIZEY; i++)
	{
		for(int j = 0; j < LEVEL_WIDTH / SIZEX; j++)
		{
			if(Manager :: map[i][j] != 0)
			{
				element.x = j * SIZEX;
				element.y = i * SIZEY;
				if(checkCollision(&element, &camera))
					applySurface(element.x - camera.x, element.y - camera.y, getElement(Manager :: map[i][j]), screen);
			}
		}
	}
}
bool MapIO :: checkCollision(SDL_Rect* A, SDL_Rect* B)
{
	int leftA, leftB;
	int rightA, rightB;
	int topA, topB;
	int bottomA, bottomB;

	leftA = A->x;
	rightA = A->x + A->w;
	topA = A->y;
	bottomA = A->y + A->h;

	leftB = B->x;
	rightB = B->x + B->w;
	topB = B->y;
	bottomB = B->y + B->h;

	if(bottomA <= topB)
		return false;
	if(topA >= bottomB)
		return false;
	if(rightA <= leftB)
		return false;
	if(leftA >= rightB)
		return false;

	return true;
}

SDL_Rect* MapIO :: getCamera()
{
	return &camera;
}

TTF_Font* MapIO :: loadFont(string filePath, int size)
{
	TTF_Font* font = TTF_OpenFont(filePath.c_str(), size);
	if(!font)
	{
		cerr << "[Error]: " << SDL_GetError() << endl;
		exit(1);
	}
	
	return font;
}

SDL_Surface* MapIO :: loadImg(string filePath)
{
	SDL_Surface* loadedImg = NULL;
	SDL_Surface* optimizedImg = NULL;

	loadedImg = IMG_Load(filePath.c_str());

	if(!loadedImg)
	{
		cerr << "[ERROR]: " << SDL_GetError() << endl;
		exit(1);
	}

	optimizedImg = SDL_DisplayFormat(loadedImg);
	SDL_FreeSurface(loadedImg);

	if(!optimizedImg)
	{
		cerr << "[ERROR]: " << SDL_GetError() << endl;
		exit(1);
	}

	return optimizedImg;
}

string MapIO :: conToString(int n)
{
	stringstream sstream;
	sstream << n;
	return sstream.str();
}

void MapIO :: setBg()
{
	int x = 0;
	int y = 0;

	for(int i = 0; i < BG_NUM; i++)
	{
		bg[i] = new Background(x, y, background);
		x += background->w;
	}
}

void MapIO :: loadElement()
{
	string filePath;

	grass = loadImg("pics\\grass1.bmp");
	SDL_SetColorKey(grass, SDL_RLEACCEL|SDL_SRCCOLORKEY, SDL_MapRGB(grass->format, 250, 250, 250));

	for(int i = 0; i < BIRD_NUM; i++)
	{
		filePath = "pics\\bird" + conToString(i+1)+ ".bmp";
		bird[i] = loadImg(filePath);
		SDL_SetColorKey(bird[i], SDL_RLEACCEL|SDL_SRCCOLORKEY, SDL_MapRGB(bird[i]->format, 250, 250, 250));
	}
	
	egg = loadImg("pics\\egg.bmp");
	SDL_SetColorKey(egg, SDL_RLEACCEL|SDL_SRCCOLORKEY, SDL_MapRGB(egg->format, 250, 250, 250));

	helmet = loadImg("pics\\helmet.bmp");
	SDL_SetColorKey(helmet, SDL_RLEACCEL|SDL_SRCCOLORKEY, SDL_MapRGB(helmet->format, 250, 250, 250));

	spine = loadImg("pics\\spine.bmp");
	SDL_SetColorKey(spine, SDL_RLEACCEL|SDL_SRCCOLORKEY, SDL_MapRGB(spine->format, 250, 250, 250));

	pig1 = loadImg("pics\\pig1.bmp");
	SDL_SetColorKey(pig1, SDL_RLEACCEL|SDL_SRCCOLORKEY, SDL_MapRGB(pig1->format, 250, 250, 250));
}

SDL_Surface* MapIO :: getElement(int n)
{
	switch(n)
	{
	case 0:
		return bird[0];
	case 1:
		return bird[1];
	case 2:
		return bird[2];
	case 3:
		return bird[3];
	case 4:
		return bird[4];
	case 5:
		return bird[5];
	case 6:
		return egg;
	case 7:
		return grass;
	case 8:
		return helmet;
	case 9:
		return spine;
	case 10:
		return pig1;
	}

	return NULL;
}